#region imported Namespaces
using System;
using System.Data;
using System.Data.SqlClient;
using System.Text;

using BO = PHSRAG.Insight21.BusinessObjects;
using DataAccess = PHSRAG.Utility.DataAccess;
using Utility = PHSRAG.Utility;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using GenerateKey = PHSRAG.Insight21.BusinessObjects.ModuleKey;
using PHSRAG.Insight21.InsightUtilities;
#endregion

namespace PHSRAG.Insight21.Admin
{
	/// <summary>
	/// The OrganizationAccessRights business object represents a user's access rights to 
	/// resources belonging to individual organizations.As of Version 2.1 those resources 
	/// can be protocols and/or agreements.
	/// </summary>
	public class OrganizationAccessRights : BO.TransactionalBusinessObject
	{
		#region Constants
		private const string OrganizationAccessRightsTableName = "OrganizationAccessRights";
		private const string OrganizationListTableName = "OrganizationList";
		private static string OrganizationAccessRightsKey = GenerateKey.MakeKey("OrganizationAccessRights_78756975-952F-4b3e-AB0E-D84B9EA6EACB",GenerateKey.Admin);
		#endregion

		#region Instance Variables
		/// <summary>SqlCommand used to update/insert organization rights in the database</summary>
		private SqlCommand	updateCommand;
		/// <summary>SqlCommand used to delete organization rights in the database</summary>
		private SqlCommand	deleteCommand;
		#endregion

		#region Public Properties

		/// <summary>
		/// Gets the DataTable that contains a users organization access rights details by module
		/// and access right type.
		/// </summary>
		public DataTable Details
		{
			get 
			{
				return DataContainer.Tables[OrganizationAccessRightsTableName];
			}
		}

		/// <summary>
		/// Gets DataTable that is essentially a list of all the organizations that a user has access to.
		/// </summary>
		public DataTable OrganizationList
		{
			get 
			{
				return DataContainer.Tables[OrganizationListTableName];
			}
			set 
			{
				if (DataContainer.Tables.Contains(OrganizationListTableName))
					DataContainer.Tables.Remove(OrganizationListTableName);

				DataContainer.Tables.Add(value);
			}
		}
		#endregion

		#region Constructor
		/// <summary>
		/// Initialize the state of this object and create commands to handle insert/delete/update.
		/// </summary>
		public OrganizationAccessRights(DataSet dataSet, ICachePolicy cachePolicy) : base(cachePolicy)
		{
			DataContainer = dataSet;
			CreateCommands();
		}
		#endregion

        #region Public Methods
        /// <summary>
        /// Returns the true count of all organizations the user has access to by module.
        /// Includes children in count.
        /// </summary>
        /// <param name="module">Module name the caller is interested in</param>
        /// <returns>int</returns>
        public int GetOrganizationAccessCount(string module)
        {
            if (!DataContainer.Tables.Contains(OrganizationListTableName))
                throw new ApplicationException("OrganizationAccessRights not properly loaded.");

            int returnValue = 0;
            foreach (DataRow row in DataContainer.Tables[OrganizationListTableName].Rows)
            {
                int rightBitMask = Int32.Parse(row["RightBitMask"].ToString());
                switch (module)
                {
                    case Constants.Modules.Animals:
                        if ((rightBitMask & Convert.ToInt32(Security.Enumerations.AccessRightBit.ViewAnimalsProtocolInformation.ToString("d"))) > 0
                            || (rightBitMask & Convert.ToInt32(Security.Enumerations.AccessRightBit.EditAnimalsProtocolInformation.ToString("d"))) > 0
                            || (rightBitMask & Convert.ToInt32(Security.Enumerations.AccessRightBit.ManageAnimalsProtocolInformation.ToString("d"))) > 0)
                        {
                            returnValue += Int32.Parse(row["Children"].ToString());
                        }
                        break;
                    case Constants.Modules.Humans:
                        if ((rightBitMask & Convert.ToInt32(Security.Enumerations.AccessRightBit.ViewProtocolInformation.ToString("d"))) > 0
                            || (rightBitMask & Convert.ToInt32(Security.Enumerations.AccessRightBit.EditProtocolInformation.ToString("d"))) > 0
                            || (rightBitMask & Convert.ToInt32(Security.Enumerations.AccessRightBit.ManageProtocolInformation.ToString("d"))) > 0)
                        {
                            returnValue += Int32.Parse(row["Children"].ToString());
                        }
                        break;
                    case Constants.Modules.Agreements:
                        if ((rightBitMask & Convert.ToInt32(Security.Enumerations.AccessRightBit.ViewFinancialInformation.ToString("d"))) > 0
                            || (rightBitMask & Convert.ToInt32(Security.Enumerations.AccessRightBit.ViewSalaryInformation.ToString("d"))) > 0
                            || (rightBitMask & Convert.ToInt32(Security.Enumerations.AccessRightBit.ViewAccess.ToString("d"))) > 0
                            || (rightBitMask & Convert.ToInt32(Security.Enumerations.AccessRightBit.ViewPendingAgreements.ToString("d"))) > 0
                            || (rightBitMask & Convert.ToInt32(Security.Enumerations.AccessRightBit.ViewPatientCareDetails.ToString("d"))) > 0)
                        {
                            returnValue += Int32.Parse(row["Children"].ToString());
                        }
                        break;
                    default:
                        throw new ApplicationException(string.Format("Module:{0} not implemented in GetOrganizationAccessCount.", module));
                }
            }
            return returnValue;
        }
        #endregion
        
        #region Base Methods
        public override void Cache()
		{
			CachePolicy.Cache(OrganizationAccessRightsKey, this);
		}

		public override void UnCache()
		{
			CachePolicy.UnCache(OrganizationAccessRightsKey);
		}

		/// <summary>
		/// Loads the data container with a domain user's organization access rights. If 
		/// a keygiver id is specified, the result set is limited to the keygiver's 
		/// organizations.  It is possible that the user does not have any organization rights
		/// resulting in an empty result set.
		/// </summary>
		/// <param name="connectionString">The connection string to the data source.</param>
		/// <param name="args">Arguments that are expected to be passed into the method are:
		///						DomainUserId - represents the user who's direct rights we are loading.
		///						KeyGiverDomainUserID - if we need to filter the resultset to only those
		///										org rights particular domainuser is keygiver for, otherwise 0.
		///</param>
		public override void Load( string connectionString, params object[] args )
		{
			if ( args.Length != 2 )
			{
				throw new Exception ("OrganizationAccessRights Load expects two arguments." );
			}		

			try
			{	
				Utility.DataAccess.LoadDataSet(DataContainer, OrganizationAccessRightsTableName, 
					connectionString, "GetUserOrganizationAccessRights",
					Utility.DataAccess.BuildSqlParameterArray("@domainUserId", SqlDbType.Int, (int)args[0]
					,"@keyGiverDomainUserId", SqlDbType.Int, (int)args[1]));

				if ( !DataContainer.Tables.Contains(OrganizationAccessRightsTableName) )
					throw new Exception("Failed to organization access rights information.");

				Utility.DataAccess.LoadDataSet(DataContainer, OrganizationListTableName, 
					connectionString, "GetUserOrganizationAccessRightsCOSDetails",
					Utility.DataAccess.BuildSqlParameterArray("@domainUserId", SqlDbType.Int, (int)args[0]
					,"@keyGiverDomainUserId", SqlDbType.Int, (int)args[1]));

				if ( !DataContainer.Tables.Contains(OrganizationListTableName) )
					throw new Exception("Failed to organization access rights information.");

			}
			catch( Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog ("OrganizationAccessRights", e, true, Utility.ExceptionReport.ReportType.Error);
				throw e;
			}
		}

		/// <summary>
		/// Persists ApplicationUser state to the database.
		/// </summary>
		/// <param name="connectionString">Specifies database connection information.</param>
		public override void Save(SqlTransaction transaction, params object[] args)
		{
			try
			{
				ExecuteUpdate(transaction);
			}
			catch (Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog ("OrganizationAccessRights", e, true, Utility.ExceptionReport.ReportType.Error);
				throw e;
			}
		}

		#endregion

		#region Private Methods
		/// <summary>
		/// Create the set of SqlCommand objects used for the deletion, and updates (updates/inserts) made on
		/// the associated DataTable. Notice that each command is initialized to invoke a stored
		/// procedure implying that each command may have its own set of parameters in line with that
		/// stored procedure.
		/// </summary>
		private void CreateCommands()
		{
			updateCommand = new SqlCommand();
			updateCommand.CommandText = "UpdateOrganizationAccess";
			updateCommand.CommandType = CommandType.StoredProcedure;
			updateCommand.CommandTimeout = Convert.ToInt32(Utility.Settings.GetKeyValue("Database.Insight.CommandTimeout", "0"));
			updateCommand.Parameters.Add("@domainUserId", SqlDbType.Int).SourceColumn = "FwkDomainUserId";
			updateCommand.Parameters.Add("@domainOrganizationId", SqlDbType.Int).SourceColumn = "FwkDomainOrganizationId";
			updateCommand.Parameters.Add("@isRecursive", SqlDbType.Bit).SourceColumn = "IsRecursive";
			updateCommand.Parameters.Add("@accessRightBitmask", SqlDbType.Int).SourceColumn = "RightBitmask";

			deleteCommand = new SqlCommand();
			deleteCommand.CommandText = "DeleteOrganizationRights";
			deleteCommand.CommandType = CommandType.StoredProcedure;
			deleteCommand.CommandTimeout = Convert.ToInt32(Utility.Settings.GetKeyValue("Database.Insight.CommandTimeout", "0"));
			deleteCommand.Parameters.Add("@domainUserId", SqlDbType.Int).SourceColumn = "FwkDomainUserId";
			deleteCommand.Parameters.Add("@orgId", SqlDbType.Int).SourceColumn = "FwkDomainOrganizationId";
		}

		/// <summary>
		/// Hits the database to persist the changes to the DataContainer.
		/// </summary>
		/// <param name="connection"></param>
		private void ExecuteUpdate(SqlTransaction transaction)
		{
			SqlDataAdapter adapter = new SqlDataAdapter();

			deleteCommand.Connection = transaction.Connection;				
			updateCommand.Connection = transaction.Connection;				

			deleteCommand.Transaction = transaction;
			updateCommand.Transaction = transaction;

			adapter.DeleteCommand = deleteCommand;
			adapter.UpdateCommand = updateCommand;
			adapter.InsertCommand = updateCommand;

			adapter.Update(DataContainer, OrganizationListTableName);
		}
			

		#endregion
	}
}
